using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Text;
using NUnit.Framework;

namespace ODX.LazyUnitTester
{

    public static class LUT
    {
        private static string testPath = @"D:\ODX.Tests";
        private static bool firstCall = true;

        public delegate void Tester();

        public static void Init()
        {
            firstCall = true;
        }

        public static void Execute(Tester test)
        {
            test();

            string testFile = GetTestFileName(test.Method);
            string tmpFile = GetTempFileName(test.Method);

            using (StreamReader tst = new StreamReader(testFile))
            {
                string tstStr = tst.ReadToEnd();
                using (StreamReader tmp = new StreamReader(tmpFile))
                {
                    string tmpStr = tmp.ReadToEnd();
                    if (tmpStr != tstStr)
                    {
                        Console.WriteLine("---------------------------------------------------------");
                        Console.WriteLine(tstStr);
                        throw new Exception("Results do not match!");
                    }
                }
            }
        }

        private static void GetFileNames(out string testFile, out string tmpFile)
        {
            testFile = tmpFile = null;

            StackTrace st = new StackTrace();
            foreach (StackFrame sf in st.GetFrames())
            {
                MethodBase mi = sf.GetMethod();
                TestAttribute[] attrs_test = (TestAttribute[])mi.GetCustomAttributes(typeof(TestAttribute), true);
                if (attrs_test.Length > 0)
                    tmpFile = GetTempFileName(mi);

                TestBodyAttribute[] attrs_body = (TestBodyAttribute[])mi.GetCustomAttributes(typeof(TestBodyAttribute), true);
                if (attrs_body.Length > 0)
                    testFile = GetTestFileName(mi);
            }

            if (testFile == null && tmpFile == null )
                throw new Exception("Can't Find running test!");
        }

        private static string GetTempFileName(MethodBase mi)
        {
            return Path.Combine(testPath, mi.ReflectedType.FullName + ".tmp.txt");
        }

        private static string GetTestFileName(MethodBase mi)
        {
            return Path.Combine(testPath, mi.ReflectedType.FullName + ".txt");
        }

        public static void WriteLine(string format, params object[] values)
        {
            DoWrite(format, values, true);
        }
        public static void WriteLine(params object[] values)
        {
            DoWrite(GetFormat(values.Length), values, true);
        }

        public static void Write(string format, params object[] values)
        {
            DoWrite(format, values, false);
        }

        public static void Write(params object[] values)
        {
            DoWrite(GetFormat(values.Length), values, false);
        }

        private static string GetFormat(int length)
        {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < length; i++)
                sb.Append("{").Append(i).Append("}");
            return sb.ToString();
        }

        private static void DoWrite(string format, object[] values, bool newLine)
        {
            Console.Write(format, values);
            if ( newLine )
                Console.WriteLine();

            if (!Directory.Exists(testPath))
                return;

            string testFile;
            string tmpFile;
            GetFileNames(out testFile, out tmpFile);
            using (StreamWriter sw = new StreamWriter(tmpFile ?? testFile, !firstCall))
            {
                sw.Write(format, values);
                if (newLine)
                    sw.WriteLine();
            }

            firstCall = false;
        }

    }

    public class TestBodyAttribute : Attribute{}
}
